
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       perf_counter.h
  * @author     baiyang
  * @date       2023-3-20
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/
/**
 * Counter types.
 */
enum perf_counter_type {
    PC_COUNT,       /**< count the number of times an event occurs */
    PC_ELAPSED,     /**< measure the time elapsed performing an event */
    PC_INTERVAL     /**< measure the interval between instances of an event */
};

struct perf_ctr_header;
typedef struct perf_ctr_header* perf_counter_t;
/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
 * Create a new local counter.
 *
 * @param type            The type of the new counter.
 * @param name            The counter name.
 * @return            Handle for the new counter, or NULL if a counter
 *                could not be allocated.
 */
perf_counter_t    perf_alloc(enum perf_counter_type type, const char *name);

/**
 * Get the reference to an existing counter or create a new one if it does not exist.
 *
 * @param type            The type of the counter.
 * @param name            The counter name.
 * @return            Handle for the counter, or NULL if a counter
 *                could not be allocated.
 */
perf_counter_t    perf_alloc_once(enum perf_counter_type type, const char *name);

/**
 * Free a counter.
 *
 * @param handle        The performance counter's handle.
 */
void        perf_free(perf_counter_t handle);

/**
 * Count a performance event.
 *
 * This call only affects counters that take single events; PC_COUNT, PC_INTERVAL etc.
 *
 * @param handle        The handle returned from perf_alloc.
 */
void        perf_count(perf_counter_t handle);

/**
 * Begin a performance event.
 *
 * This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
 *
 * @param handle        The handle returned from perf_alloc.
 */
void        perf_begin(perf_counter_t handle);

/**
 * End a performance event.
 *
 * This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
 * If a call is made without a corresponding perf_begin call, or if perf_cancel
 * has been called subsequently, no change is made to the counter.
 *
 * @param handle        The handle returned from perf_alloc.
 */
void        perf_end(perf_counter_t handle);

/**
 * Register a measurement
 *
 * This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
 * If a call is made without a corresponding perf_begin call. It sets the
 * value provided as argument as a new measurement.
 *
 * @param handle        The handle returned from perf_alloc.
 * @param elapsed        The time elapsed. Negative values lead to incrementing the overrun counter.
 */
void        perf_set_elapsed(perf_counter_t handle, int64_t elapsed);

/**
 * Register a measurement
 *
 * This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
 * If a call is made without a corresponding perf_begin call. It sets the
 * value provided as argument as a new measurement.
 *
 * @param handle        The handle returned from perf_alloc.
 * @param time            The time for the interval.
 */
void        perf_count_interval(perf_counter_t handle, uint64_t time);

/**
 * Set a counter
 *
 * This call applies to counters of type PC_COUNT. It (re-)sets the count.
 *
 * @param handle        The handle returned from perf_alloc.
 * @param count            The counter value to be set.
 */
void        perf_set_count(perf_counter_t handle, uint64_t count);

/**
 * Cancel a performance event.
 *
 * This call applies to counters that operate over ranges of time; PC_ELAPSED etc.
 * It reverts the effect of a previous perf_begin.
 *
 * @param handle        The handle returned from perf_alloc.
 */
void        perf_cancel(perf_counter_t handle);

/**
 * Reset a performance counter.
 *
 * This call resets performance counter to initial state
 *
 * @param handle        The handle returned from perf_alloc.
 */
void        perf_reset(perf_counter_t handle);

/**
 * Print one performance counter to stdout
 *
 * @param handle        The counter to print.
 */
void        perf_print_counter(perf_counter_t handle);

/**
 * Print one performance counter to a buffer.
 *
 * @param buffer            buffer to write to
 * @param length            buffer length
 * @param handle            The counter to print.
 * @param return            number of bytes written
 */
int        perf_print_counter_buffer(char *buffer, int length, perf_counter_t handle);

/**
 * Print all of the performance counters.
 */
void        perf_print_all(void);


typedef void (*perf_callback)(perf_counter_t handle, void *user);

/**
 * Iterate over all performance counters using a callback.
 *
 * Caution: This will aquire the mutex, so do not call any other perf_* method
 * that aquire the mutex as well from the callback (If this is needed, configure
 * the mutex to be reentrant).
 *
 * @param cb callback method
 * @param user custom argument for the callback
 */
void    perf_iterate_all(perf_callback cb, void *user);

/**
 * Reset all of the performance counters.
 */
void        perf_reset_all(void);

/**
 * Return current event_count
 *
 * @param handle        The counter returned from perf_alloc.
 * @return            event_count
 */
uint64_t    perf_event_count(perf_counter_t handle);

/**
 * Return current mean
 *
 * @param handle        The handle returned from perf_alloc.
 * @param return        mean
 */
float        perf_mean(perf_counter_t handle);

/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



